package _binary_tree

import common.TreeNode
import org.junit.Assert
import org.junit.Test

/**
 * https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/description
 *
 * 题型 ： 二叉树的前序遍历
 *
 * ```
 * 1022. 从根到叶的二进制数之和
 * 给出一棵二叉树，其上每个结点的值都是 0 或 1 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。
 * 例如，如果路径为 0 -> 1 -> 1 -> 0 -> 1，那么它表示二进制数 01101，也就是 13 。
 * 对树上的每一片叶子，我们都要找出从根到该叶子的路径所表示的数字。
 * 返回这些数字之和。题目数据保证答案是一个 32 位 整数。
 *
 * 示例 1：
 * 输入：root = [1,0,1,0,1,0,1]
 * 输出：22
 * 解释：(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
 *
 * 示例 2：
 * 输入：root = [0]
 * 输出：0
 *
 * 示例 3：
 * 输入：root = [1,null,0]
 * 输出：2
 *
 * 提示：
 * 树中的节点数在 [1, 1000] 范围内
 * Node.val 仅为 0 或 1
 * ```
 */
class leetcode_1022 {
    @Test
    fun test_2() {
        val root = TreeNode(0)

        val actual = sumRootToLeaf(root)
        val expected = 0

        Assert.assertEquals(expected, actual)
    }

    @Test
    fun test_3() {
        val root = TreeNode(1)
        root.right = TreeNode(0)

        val actual = sumRootToLeaf(root)
        val expected = 2

        Assert.assertEquals(expected, actual)
    }


    private fun sumRootToLeaf(root: TreeNode?): Int {
        /**
        题型 ： 二叉树的前序遍历

        思路：
        第1步：利用前序遍历收集所有paths。当节点的左右孩子为null，收集path
        第2步：循环所有paths，每一条path 转成 二进制整型，然后累加。

        空间复杂度：O(n)
        时间复杂度：O(n)

         */
        val paths: ArrayList<String> = ArrayList()
        collectPath(root, paths, "")
        // println(paths)
        val sum = sum(paths)
        return sum
    }

    private fun collectPath(root: TreeNode?, paths: ArrayList<String>, path: String) {
        // 1 确认函数参数以及返回值
        // 2 确认终止条件
        if (root == null) {
            return
        }

        // 3 确认单次递归的处理逻辑 : 前序遍历
        var targetPath = path + root.`val`
        // 中
        if (root.left == null && root.right == null) {
            paths.add(targetPath)
            return
        }

        // 左
        collectPath(root.left, paths, targetPath)

        // 右
        collectPath(root.right, paths, targetPath)
    }

    private fun sum(paths: ArrayList<String>): Int {
        var sum: Int = 0
        for (n in paths) {
            // TODO: 二进制string -> 二进制整型，
            sum = sum + n.toInt(2)
        }
        return sum
    }
}